package com.example.common.config;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.example.common.Constants;
import com.example.common.enums.ResultCodeEnum;
import com.example.common.enums.RoleEnum;
import com.example.entity.Account;
import com.example.exception.CustomException;
import com.example.service.AdminService;
import com.example.service.StudentService;
import com.example.service.TeacherService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

/**
 * JWT 认证拦截器
 * 使用构造器注入符合 Spring Boot 3 最佳实践
 */
@Component
public class JwtInterceptor implements HandlerInterceptor {

    private static final Logger log = LoggerFactory.getLogger(JwtInterceptor.class);

    private final AdminService adminService;
    private final TeacherService teacherService;
    private final StudentService studentService;

    public JwtInterceptor(AdminService adminService, TeacherService teacherService, StudentService studentService) {
        this.adminService = adminService;
        this.teacherService = teacherService;
        this.studentService = studentService;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 1. 从 HTTP 请求的 header 中获取 token
        String token = request.getHeader(Constants.TOKEN);
        if (StrUtil.isEmpty(token)) {
            // 如果没拿到，从参数里再拿一次
            token = request.getParameter(Constants.TOKEN);
        }

        // 2. 开始执行认证
        if (StrUtil.isEmpty(token)) {
            throw new CustomException(ResultCodeEnum.TOKEN_INVALID_ERROR);
        }

        // 3. 解析 token 并验证
        Account account = parseAndValidateToken(token);

        // 4. 验证用户密码签名
        verifyTokenSignature(token, account);

        return true;
    }

    /**
     * 解析并验证 token，获取用户信息
     */
    private Account parseAndValidateToken(String token) {
        try {
            // 解析 token 获取存储的数据
            String userRole = JWT.decode(token).getAudience().get(0);
            String[] parts = userRole.split("-");
            String userId = parts[0];
            String role = parts[1];

            // 根据角色查询对应的用户信息
            return switch (RoleEnum.valueOf(role)) {
                case ADMIN -> adminService.selectById(Integer.valueOf(userId));
                case TEACHER -> teacherService.selectById(Integer.valueOf(userId));
                case STUDENT -> studentService.selectById(Integer.valueOf(userId));
            };
        } catch (Exception e) {
            log.error("Token 解析失败", e);
            throw new CustomException(ResultCodeEnum.TOKEN_CHECK_ERROR);
        }
    }

    /**
     * 验证 token 签名
     */
    private void verifyTokenSignature(String token, Account account) {
        if (ObjectUtil.isNull(account)) {
            throw new CustomException(ResultCodeEnum.USER_NOT_EXIST_ERROR);
        }

        try {
            // 用户密码加签验证 token
            JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(account.getPassword())).build();
            jwtVerifier.verify(token);
        } catch (JWTVerificationException e) {
            log.error("Token 验证失败", e);
            throw new CustomException(ResultCodeEnum.TOKEN_CHECK_ERROR);
        }
    }
}